Strings
In Rust, text handling is powerful but strict. This is because Rust guarantees memory safety and Unicode correctness.
Rust mainly uses two types for text:
String– an owned, growable string&str– a string slice, borrowed view of a string
Understanding the difference is crucial.
String in Rust
- A heap-allocated, growable, mutable string
- Stores text as UTF-8
- Owns its data
let mut s = String::from("Hello");
Key Characteristics
| Feature | String |
|---|---|
| Memory | Heap |
| Mutable | ✅ Yes |
| Ownership | Owns the data |
| UTF-8 | ✅ Yes |
Creating a String
let s1 = String::from("Hello");
let s2 = "World".to_string();
Both create a String.
Modifying a String
Appending text
let mut s = String::from("Hello");
s.push('!'); // single character
s.push_str(" World"); // string slice
Result: Hello! World
Concatenation: Using + operator
let s1 = String::from("Hello ");
let s2 = String::from("Rust");
let s3 = s1 + &s2;
Important:
s1is moveds2is borrowed
Why? Because + is actually: fn add(self, s: &str) -> String
Using format! macro (recommended)
let s1 = String::from("Hello");
let s2 = String::from("Rust");
let s3 = format!("{} {}", s1, s2);
- No ownership issues
- Cleaner code
String Slices (&str)
A string slice is a reference to part (or all) of a string.
let s = String::from("Hello World");
let slice = &s[0..5];
slice is of type &str
Key Characteristics
| Feature | &str |
|---|---|
| Ownership | ❌ No |
| Mutable | ❌ No |
| Memory | Stack reference |
| UTF-8 | ✅ Yes |
String Literals Are Slices
let s = "Hello Rust";
This is not a String. It is a &'static str (stored in the binary).
String Slicing Syntax
let s = String::from("Hello World");
let hello = &s[0..5];
let world = &s[6..11];
Shorthand versions
let hello = &s[..5]; // from start
let world = &s[6..]; // to end
let full = &s[..]; // entire string
UTF-8 and Slicing Rules (Very Important!)
Rust strings are UTF-8 encoded, so indexing is NOT allowed.
This is illegal:
let s = String::from("Hello");
let c = s[0]; // ❌ compile-time error
Why?
- Characters may take more than 1 byte
Invalid UTF-8 Slice Example
let s = String::from("नमस्ते");
let slice = &s[0..1]; // ❌ runtime panic
Because characters like न use multiple bytes.
Safe Way: Iterate Over Characters
let s = String::from("नमस्ते");
for c in s.chars() {
println!("{}", c);
}
Converting Between String and &str
String ➡️ &str
let s = String::from("Hello");
let slice: &str = &s;
&str ➡️ String
let slice = "Hello";
let s = slice.to_string();
or
let s = String::from(slice);
Function Parameters: Best Practice
Prefer &str over String
fn greet(name: &str) {
println!("Hello, {}", name);
}
Why?
- Accepts both
Stringand&str - Avoids unnecessary ownership transfer
let s = String::from("Rust");
greet(&s);
greet("World");
Summary Table
| Feature | String | &str |
|---|---|---|
| Owns data | ✅ | ❌ |
| Mutable | ✅ | ❌ |
| Heap allocated | ✅ | ❌ |
| UTF-8 | ✅ | ✅ |
| Common use | Dynamic text | Function parameters |